﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Threading;
using System.Windows.Threading;
using System.ComponentModel;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Animation;
using System.Diagnostics;
using System.Windows.Documents;

namespace WeatherReaderMVC
{
    /// <summary>
    /// Interaction logic for WeatherReaderUI.xaml
    /// </summary>
    public partial class WeatherReaderUI : UserControl
    {

        #region API

        public void ShowButtons(bool show)
        {
            if (show)
            {
                ButtonsBorder.Visibility = Visibility.Visible;
            }
            else
            {
                ButtonsBorder.Visibility = Visibility.Collapsed;
            }
        }

        private void HideMinMax()
        {
            minmaxBtn.Visibility = Visibility.Hidden;
            ButtonsBorder.Height = SettingsBtn.ActualHeight + 20;
        }

        //public void MakeMini(bool mini)
        //{
        //    if (isMin == mini)
        //        return;
        //    minmaxBtn_Click(new Object(), new RoutedEventArgs());
        //}

        #endregion

        #region PrivateFields

        private IWeatherDataProvider weatherProvider;
        private ObjectDataProvider searchResultsProvider;
        private ObjectDataProvider weatherReportProvider;
        private Location currentLocation;
        private UnitsSystems unitsSystem;

        // Members used for threading the search
        private string pendingSearchQuery;
        // This could be considered the lock on the searchResultsProvider
        private bool aSearchRequestIsInProgress = false;

        // No need to thread the weather retrieval process
        //// Members used for threading the weather
        //private bool aWeatherRequestIsInProgress = false;

        #endregion



        public bool Minimized
        {
            get { return (bool)GetValue(MinimizedProperty); }
            set { SetValue(MinimizedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Minimized.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MinimizedProperty =
            DependencyProperty.Register("Minimized", typeof(bool), typeof(WeatherReaderUI), new UIPropertyMetadata(false, new PropertyChangedCallback(MinimizedPropertyChanged)));

        private static void MinimizedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if ((bool)args.NewValue == true)
            {
                ((WeatherReaderUI)sender).MiniGrid.Visibility = Visibility.Visible;
                ((WeatherReaderUI)sender).MainGrid.Visibility = Visibility.Collapsed;
            }
        }


        public bool HideMinimizeButton
        {
            get { return (bool)GetValue(HideMinimizeButtonProperty); }
            set { SetValue(HideMinimizeButtonProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HideMinimizeButton.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HideMinimizeButtonProperty =
            DependencyProperty.Register("HideMinimizeButton", typeof(bool), typeof(WeatherReaderUI), new UIPropertyMetadata(false,new PropertyChangedCallback(HideMinimizeButtonPropertyChanged)));

        private static void HideMinimizeButtonPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if((bool)args.NewValue == true)
            {
                ((WeatherReaderUI)sender).HideMinMax();

            }
        }
        

        #region Constructors

        public WeatherReaderUI()
        {   
            InitializeComponent();

            currentLocation = new MsnLocation();
            loadSettings();
            //ShowButtons(false);
            //MakeMini(true);

            weatherProvider = new MsnWeatherDataProvider();
            searchResultsProvider = FindResource("searchResults") as ObjectDataProvider;
            weatherReportProvider = FindResource("weatherReport") as ObjectDataProvider;
            weatherReportProvider.ObjectInstance = weatherProvider.GetLatestWeatherReport(currentLocation, unitsSystem);
            SettingsPopup.Opened += new EventHandler(SettingsPopup_Opened);
            SettingsPopup.Closed += new EventHandler(SettingsPopup_Closed);
            SettingsPopup.PlacementTarget = WeatherReader;
            SettingsPopup.HorizontalAlignment = HorizontalAlignment.Left;
            SettingsPopup.HorizontalOffset = -50 ;
            SettingsPopup.VerticalOffset = -100;

            retract = FindResource("RetractFullWindow") as Storyboard;
            retract.CurrentTimeInvalidated += new EventHandler(retract_CurrentTimeInvalidated);
            retract.AutoReverse = true;
            retract.Completed += new EventHandler(retract_Completed);
        }


        bool completedAnimation = true;

        void retract_Completed(object sender, EventArgs e)
        {
            completedAnimation = true;
            minmaxBtn.IsEnabled = true;
            SettingsBtn.IsEnabled = true;
        }

        void SettingsPopup_Closed(object sender, EventArgs e)
        {
            retract.Resume(this);
        }

        void SettingsPopup_Opened(object sender, EventArgs e)
        {
            if (completedAnimation)
            {
                minmaxBtn.IsEnabled = false;
                SettingsBtn.IsEnabled = false;
                retract.Begin(this, true);
                completedAnimation = false;
            }
        }

        void retract_CurrentTimeInvalidated(object sender, EventArgs e)
        {
            TimeSpan t = (TimeSpan)retract.GetCurrentTime(this);
            Console.WriteLine(t.ToString());
            if ((t.Milliseconds >= 970) && (SettingsPopup.IsOpen==true))
            {
                retract.Pause(this);
            }
        }

        #endregion

        #region PrivateMethods

        private void loadSettings ()
        {
            ((MsnLocation)currentLocation).LocationCode = Settings1.Default.LocationCode;
            currentLocation.FullName = Settings1.Default.FullName;
            currentLocation.Country = Settings1.Default.Country;
            currentLocation.State = Settings1.Default.State;
            currentLocation.City = Settings1.Default.City;
            currentLocation.ZipCode = Settings1.Default.ZipCode;
            currentLocation.Longitude = Settings1.Default.Longitude;
            currentLocation.Latitude = Settings1.Default.Latitude;

            unitsSystem = (Settings1.Default.DegreeType == 'F') ? UnitsSystems.Imperial : UnitsSystems.Metric;
        }

        private void storeSettings()
        {
            Settings1.Default.LocationCode = ((MsnLocation)currentLocation).LocationCode;
            Settings1.Default.FullName = currentLocation.FullName;
            Settings1.Default.Country = currentLocation.Country;
            Settings1.Default.State = currentLocation.State;
            Settings1.Default.City = currentLocation.City;
            

            // TODO: Clean up the following 3 messy lines (use correct null values)
            int zip; double lon, lat;
            Settings1.Default.ZipCode = (int.TryParse(currentLocation.ZipCode.ToString(), out zip)) ? zip : -1;
            Settings1.Default.Longitude = (double.TryParse(currentLocation.Longitude.ToString(), out lon)) ? lon : -1000;
            Settings1.Default.Latitude = (double.TryParse(currentLocation.Latitude.ToString(), out lat)) ? lat : -1000;

            Settings1.Default.DegreeType = (UnitsSystems.Imperial == unitsSystem) ? 'F' : 'C';
        }

        private BackgroundWorker backgroundHandleSearchRequest;
        private void searchQueryTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            string query = ((TextBox)sender).Text.Trim();
            if (!(query.Equals(pendingSearchQuery)))
            {
                pendingSearchQuery = query;
                if (!aSearchRequestIsInProgress)
                {
                    aSearchRequestIsInProgress = true;
                    backgroundHandleSearchRequest = new BackgroundWorker();
                    backgroundHandleSearchRequest.DoWork += new DoWorkEventHandler(handleSearchRequest);
                    backgroundHandleSearchRequest.RunWorkerAsync();
                }
            }
        }

        private void handleSearchRequest(object sender, DoWorkEventArgs e) 
        {
            string currentSearchQuery = pendingSearchQuery;
            searchResultsProvider.ObjectInstance = weatherProvider.QueryLocations(currentSearchQuery);
            if (currentSearchQuery.Equals(pendingSearchQuery))
                aSearchRequestIsInProgress = false;
            else
                handleSearchRequest(sender, e);
        }

        // // fix the threading of this function
        // No threading will be used: no fix needed
        private void resultsListBox_SelectionChanged(object sender, EventArgs e)
        {
            ListBox source = sender as ListBox;
            if (source.SelectedItem == null)
                return;
            currentLocation = source.SelectedItem as Location;
            storeSettings();
            // disable the listbox before grabbing the weather data then enable it afterwards
            // source.IsEnabled = false;
            weatherReportProvider.ObjectInstance = weatherProvider.GetLatestWeatherReport(currentLocation, unitsSystem);
            // source.IsEnabled = true;

            // Used for threading: no longer needed
            //if (!aWeatherRequestIsInProgress)
            //{
            //    aWeatherRequestIsInProgress = true;
            //    BackgroundWorker backgroundHandleWeatherRequest = new BackgroundWorker();
            //    backgroundHandleWeatherRequest.DoWork += new DoWorkEventHandler(handleWeatherRequest);
            //    backgroundHandleWeatherRequest.RunWorkerAsync();
            //}
        }

        Storyboard retract;
        private void SettingsBtn_Click(object sender, RoutedEventArgs e)
        {
            SettingsPopup.IsOpen = true;
            if (UnitsSystems.Imperial == unitsSystem)
            {
                fahrenheitRadioBtn.IsChecked = true;
            }
            else
            {
                celsiusRadioBtn.IsChecked = true;
            }

//             Animation here
            //retract = FindResource("RetractFullWindow") as Storyboard;

            //retract.CurrentTimeInvalidated += new EventHandler(retract_CurrentTimeInvalidated);
            
            //retract.AutoReverse = true;
            //retract.Begin(this, true);
        }



        private void resultsListBox_PreviewMouseDoubleClick(object sender, EventArgs e)
        {
            resultsListBox_SelectionChanged(sender, e);
            OkBtn_Click(sender, e);
        }

        private void OkBtn_Click(object sender, EventArgs e)
        {
            SettingsPopup.IsOpen = false;
            storeSettings();
            Settings1.Default.Save();
            // Animation here
            //Storyboard retract = FindResource("retractFullWindow") as Storyboard;
            //retract.AutoReverse = true;
            //retract.Resume(this);
            //retract.Begin(this, true);
            //retract.Seek(this, new TimeSpan(0, 0, 0), TimeSeekOrigin.Duration);
            
        }

        private void CancelBtn_Click(object sender, EventArgs e)
        {
            SettingsPopup.IsOpen = false;
            Settings1.Default.Reload();
            loadSettings();
            weatherReportProvider.ObjectInstance = weatherProvider.GetLatestWeatherReport(currentLocation, unitsSystem);
            
            // Animation here
            //Storyboard retract = FindResource("retractFullWindow") as Storyboard;
            //retract.AutoReverse = true;
            //retract.Resume(this);
            //retract.Begin(this, true);
            //retract.Seek(this, new TimeSpan(0, 0, 0), TimeSeekOrigin.Duration);
            
        }

        private void WeatherReader_Unloaded(object sender, EventArgs e)
        {
            storeSettings();
            Settings1.Default.Save();
        }

        private void celsiusRadioBtn_Checked(object sender, EventArgs e)
        {
            unitsSystem = UnitsSystems.Metric;
            weatherReportProvider.ObjectInstance = weatherProvider.GetLatestWeatherReport(currentLocation, unitsSystem);
        }

        private void fahrenheitRadioBtn_Checked(object sender, EventArgs e)
        {
            unitsSystem = UnitsSystems.Imperial;
            weatherReportProvider.ObjectInstance = weatherProvider.GetLatestWeatherReport(currentLocation, unitsSystem);
        }

        private void minmaxBtn_Click(object sender, RoutedEventArgs e)
        {
            if (Minimized) // Maximize/Make full
            {
                Minimized = false;
                MiniGrid.Visibility = Visibility.Collapsed;
                MainGrid.Visibility = Visibility.Visible;
                //this.Width = 264;
                //this.Height = 194;
            }
            else // Minimize
            {
                Minimized = true;
                MainGrid.Visibility = Visibility.Collapsed;
                MiniGrid.Visibility = Visibility.Visible;
                //this.Width = 200;
                //this.Height = 170;
            }
        }

        private void cityHyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
        {
            string navigateUri = ((Hyperlink)sender).NavigateUri.ToString();
            // if the URI somehow came from an untrusted source, make sure to
            // validate it before calling Process.Start(), e.g. check to see
            // the scheme is HTTP, etc.
            Process.Start(new ProcessStartInfo(navigateUri));
            e.Handled = true;
        }

        #endregion

    }
}
